home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / lib / ubiquity / plugins / ubi-timezone.py < prev    next >
Text File  |  2009-10-27  |  23KB  |  567 lines

  1. # -*- coding: utf-8; Mode: Python; indent-tabs-mode: nil; tab-width: 4 -*-
  2.  
  3. # Copyright (C) 2006, 2007, 2008 Canonical Ltd.
  4. # Written by Colin Watson <cjwatson@ubuntu.com>.
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program; if not, write to the Free Software
  18. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  19.  
  20. import os
  21. import time
  22. import re
  23.  
  24. import debconf
  25. import PyICU
  26.  
  27. from ubiquity.plugin import *
  28. from ubiquity import i18n
  29. import ubiquity.tz
  30.  
  31. NAME = 'timezone'
  32. AFTER = 'language'
  33. WEIGHT = 10
  34.  
  35. class PageGtk(PluginUI):
  36.     def __init__(self, controller, *args, **kwargs):
  37.         self.controller = controller
  38.         try:
  39.             import gtk
  40.             builder = gtk.Builder()
  41.             builder.add_from_file('/usr/share/ubiquity/gtk/stepLocation.ui')
  42.             builder.connect_signals(self)
  43.             self.page = builder.get_object('stepLocation')
  44.             self.region_combo = builder.get_object('timezone_zone_combo')
  45.             self.city_combo = builder.get_object('timezone_city_combo')
  46.             self.map_window = builder.get_object('timezone_map_window')
  47.             self.setup_page()
  48.         except Exception, e:
  49.             self.debug('Could not create timezone page: %s', e)
  50.             self.page = None
  51.         self.plugin_widgets = self.page
  52.  
  53.     def set_timezone(self, timezone):
  54.         self.fill_timezone_boxes()
  55.         self.select_city(None, timezone)
  56.  
  57.     def get_timezone(self):
  58.         i = self.city_combo.get_active()
  59.         m = self.city_combo.get_model()
  60.         return m[i][1]
  61.  
  62.     def fill_timezone_boxes(self):
  63.         m = self.region_combo.get_model()
  64.         if m.get_iter_first():
  65.             return
  66.         tz = self.controller.dbfilter
  67.  
  68.         # Regions are a translated shortlist of regions, followed by full list
  69.         m.clear()
  70.         lang = os.environ['LANG'].split('_', 1)[0]
  71.         region_pairs = tz.build_shortlist_region_pairs(lang)
  72.         if region_pairs:
  73.             for pair in region_pairs:
  74.                 m.append(pair)
  75.             m.append([None, None, None])
  76.         region_pairs = tz.build_region_pairs()
  77.         for pair in region_pairs:
  78.             m.append(pair)
  79.  
  80.     def select_country(self, country):
  81.         def country_is_in_region(country, region):
  82.             if not region: return False
  83.             return country in self.controller.dbfilter.get_countries_for_region(region)
  84.  
  85.         m = self.region_combo.get_model()
  86.         iterator = self.region_combo.get_active()
  87.         got_country = m[iterator][1] == country or \
  88.                       country_is_in_region(country, m[iterator][2])
  89.         if not got_country:
  90.             iterator = m.get_iter_first()
  91.             while iterator:
  92.                 if m[iterator][0] is not None and \
  93.                    m[iterator][1] == country or \
  94.                    country_is_in_region(country, m[iterator][2]):
  95.                     self.region_combo.set_active_iter(iterator)
  96.                     break
  97.                 iterator = m.iter_next(iterator)
  98.  
  99.     def select_city(self, widget, city):
  100.         loc = self.tzdb.get_loc(city)
  101.         if not loc:
  102.             return
  103.  
  104.         self.select_country(loc.country)
  105.  
  106.         m = self.city_combo.get_model()
  107.         iterator = m.get_iter_first()
  108.         while iterator:
  109.             if m[iterator][1] == city:
  110.                 self.city_combo.set_active_iter(iterator)
  111.                 return
  112.             iterator = m.iter_next(iterator)
  113.         # We don't have a timezone selection, so don't let the user proceed.
  114.         self.controller.allow_go_forward(False)
  115.  
  116.     def setup_page(self):
  117.         import gobject, gtk
  118.         from ubiquity import timezone_map
  119.         self.tzdb = ubiquity.tz.Database()
  120.         self.tzmap = timezone_map.TimezoneMap(self.tzdb, '/usr/share/ubiquity/pixmaps/timezone')
  121.         self.tzmap.connect('city-selected', self.select_city)
  122.         self.map_window.add(self.tzmap)
  123.         self.tzmap.show()
  124.  
  125.         def is_separator(m, i):
  126.             return m[i][0] is None
  127.  
  128.         renderer = gtk.CellRendererText()
  129.         self.region_combo.pack_start(renderer, True)
  130.         self.region_combo.add_attribute(renderer, 'text', 0)
  131.         list_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
  132.         self.region_combo.set_model(list_store)
  133.         self.region_combo.set_row_separator_func(is_separator)
  134.  
  135.         renderer = gtk.CellRendererText()
  136.         self.city_combo.pack_start(renderer, True)
  137.         self.city_combo.add_attribute(renderer, 'text', 0)
  138.         city_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
  139.         self.city_combo.set_model(city_store)
  140.  
  141.     def on_region_combo_changed(self, *args):
  142.         i = self.region_combo.get_active()
  143.         m = self.region_combo.get_model()
  144.         if i is None:
  145.             return
  146.         if m[i][1]:
  147.             countries = [m[i][1]]
  148.         else:
  149.             countries = self.controller.dbfilter.get_countries_for_region(m[i][2])
  150.  
  151.         m = self.city_combo.get_model()
  152.         m.clear()
  153.  
  154.         shortlist, longlist = self.controller.dbfilter.build_timezone_pairs(countries)
  155.         for pair in shortlist:
  156.             m.append(pair)
  157.         if shortlist:
  158.             m.append([None, None])
  159.         for pair in longlist:
  160.             m.append(pair)
  161.  
  162.         default = len(countries) == 1 and self.controller.dbfilter.get_default_for_region(countries[0])
  163.         if default:
  164.             self.select_city(None, default)
  165.         else:
  166.             self.city_combo.set_active_iter(m.get_iter_first())
  167.  
  168.     def on_city_combo_changed(self, *args):
  169.         i = self.city_combo.get_active()
  170.         if i < 0:
  171.             # There's no selection yet.
  172.             return
  173.  
  174.         zone = self.get_timezone()
  175.         self.tzmap.select_city(zone)
  176.         self.controller.allow_go_forward(True)
  177.  
  178. class PageKde(PluginUI):
  179.     plugin_breadcrumb = 'ubiquity/text/breadcrumb_timezone'
  180.  
  181.     def __init__(self, controller, *args, **kwargs):
  182.         self.controller = controller
  183.         try:
  184.             from PyQt4 import uic
  185.             from PyQt4.QtGui import QVBoxLayout
  186.             from PyQt4.QtCore import SIGNAL
  187.             from ubiquity.frontend.kde_components.Timezone import TimezoneMap
  188.             self.page = uic.loadUi('/usr/share/ubiquity/qt/stepLocation.ui')
  189.             self.tzmap = TimezoneMap(self.page.map_frame)
  190.             self.page.map_frame.layout().addWidget(self.tzmap)
  191.             self.SIGNAL = SIGNAL
  192.             self.tzmap.connect(self.tzmap, self.SIGNAL("zoneChanged"), self.mapZoneChanged)
  193.             self.page.timezone_zone_combo.currentIndexChanged[int].connect(self.regionChanged)
  194.             self.page.timezone_city_combo.currentIndexChanged[int].connect(self.cityChanged)
  195.         except Exception, e:
  196.             self.debug('Could not create timezone page: %s', e)
  197.             self.page = None
  198.         self.plugin_widgets = self.page
  199.  
  200.     def refresh_timezones(self):
  201.         lang = os.environ['LANG'].split('_', 1)[0]
  202.         shortlist = self.controller.dbfilter.build_shortlist_region_pairs(lang)
  203.         longlist = self.controller.dbfilter.build_region_pairs()
  204.  
  205.         self.page.timezone_zone_combo.clear()
  206.         for pair in shortlist:
  207.             self.page.timezone_zone_combo.addItem(pair[0], pair[1])
  208.         self.page.timezone_zone_combo.insertSeparator(self.page.timezone_zone_combo.count())
  209.         for pair in longlist:
  210.             self.page.timezone_zone_combo.addItem(pair[0], pair[2])
  211.  
  212.     def populateCities(self, regionIndex):
  213.         self.page.timezone_city_combo.clear()
  214.  
  215.         code = str(self.page.timezone_zone_combo.itemData(regionIndex).toPyObject())
  216.         countries = self.controller.dbfilter.get_countries_for_region(code)
  217.         if not countries: # must have been a country code itself
  218.             countries = [code]
  219.  
  220.         shortlist, longlist = self.controller.dbfilter.build_timezone_pairs(countries)
  221.  
  222.         for pair in shortlist:
  223.             self.page.timezone_city_combo.addItem(pair[0], pair[1])
  224.         if shortlist:
  225.             self.page.timezone_city_combo.insertSeparator(self.page.timezone_city_combo.count())
  226.         for pair in longlist:
  227.             self.page.timezone_city_combo.addItem(pair[0], pair[1])
  228.  
  229.         return len(countries) == 1 and self.controller.dbfilter.get_default_for_region(countries[0])
  230.  
  231.     # called when the region(zone) combo changes
  232.     def regionChanged(self, regionIndex):
  233.         if self.controller.dbfilter is None:
  234.             return
  235.  
  236.         self.page.timezone_city_combo.currentIndexChanged[int].disconnect(self.cityChanged)
  237.         default = self.populateCities(regionIndex)
  238.         self.page.timezone_city_combo.currentIndexChanged[int].connect(self.cityChanged)
  239.  
  240.         if default:
  241.             self.tzmap.set_timezone(default)
  242.         else:
  243.             self.cityChanged(0)
  244.  
  245.     # called when the city combo changes
  246.     def cityChanged(self, cityindex):
  247.         zone = str(self.page.timezone_city_combo.itemData(cityindex).toPyObject())
  248.         self.tzmap.disconnect(self.tzmap, self.SIGNAL("zoneChanged"), self.mapZoneChanged)
  249.         self.tzmap.set_timezone(zone)
  250.         self.tzmap.connect(self.tzmap, self.SIGNAL("zoneChanged"), self.mapZoneChanged)
  251.  
  252.     def mapZoneChanged(self, loc, zone):
  253.         self.page.timezone_zone_combo.currentIndexChanged[int].disconnect(self.regionChanged)
  254.         self.page.timezone_city_combo.currentIndexChanged[int].disconnect(self.cityChanged)
  255.  
  256.         for i in range(self.page.timezone_zone_combo.count()):
  257.             code = str(self.page.timezone_zone_combo.itemData(i).toPyObject())
  258.             countries = self.controller.dbfilter.get_countries_for_region(code)
  259.             if not countries: # must have been a country code itself
  260.                 countries = [code]
  261.             if loc.country in countries:
  262.                 self.page.timezone_zone_combo.setCurrentIndex(i)
  263.                 self.populateCities(i)
  264.                 break
  265.  
  266.         for i in range(self.page.timezone_city_combo.count()):
  267.             code = str(self.page.timezone_city_combo.itemData(i).toPyObject())
  268.             if zone == code:
  269.                 self.page.timezone_city_combo.setCurrentIndex(i)
  270.                 self.cityChanged(i)
  271.                 break
  272.  
  273.         self.page.timezone_zone_combo.currentIndexChanged[int].connect(self.regionChanged)
  274.         self.page.timezone_city_combo.currentIndexChanged[int].connect(self.cityChanged)
  275.  
  276.     def set_timezone (self, timezone):
  277.         self.refresh_timezones()
  278.         self.tzmap.set_timezone(timezone)
  279.  
  280.     def get_timezone (self):
  281.         return self.tzmap.get_timezone()
  282.  
  283. class PageDebconf(PluginUI):
  284.     plugin_title = 'ubiquity/text/timezone_heading_label'
  285.  
  286. class PageNoninteractive(PluginUI):
  287.     def set_timezone(self, timezone):
  288.         """Set the current selected timezone."""
  289.         self.timezone = timezone
  290.  
  291.     def get_timezone(self):
  292.         """Get the current selected timezone."""
  293.         return self.timezone
  294.  
  295. class Page(Plugin):
  296.     def prepare(self, unfiltered=False):
  297.         clock_script = '/usr/share/ubiquity/clock-setup'
  298.         env = {'PATH': '/usr/share/ubiquity:' + os.environ['PATH']}
  299.  
  300.         if unfiltered:
  301.             # In unfiltered mode, localechooser is responsible for selecting
  302.             # the country, so there's no need to repeat the job here.
  303.             env['TZSETUP_NO_LOCALECHOOSER'] = '1'
  304.             return ([clock_script], ['PROGRESS'], env)
  305.  
  306.         self.timezones = []
  307.         self.regions = {}
  308.         self.tzdb = ubiquity.tz.Database()
  309.         self.multiple = False
  310.         try:
  311.             # Strip .UTF-8 from locale, PyICU doesn't parse it
  312.             locale = os.environ['LANG'].rsplit('.', 1)[0]
  313.             self.collator = PyICU.Collator.createInstance(PyICU.Locale(locale))
  314.         except:
  315.             self.collator = None
  316.         if not 'UBIQUITY_AUTOMATIC' in os.environ:
  317.             self.db.fset('time/zone', 'seen', 'false')
  318.             cc = self.db.get('debian-installer/country')
  319.             try:
  320.                 self.db.get('tzsetup/country/%s' % cc)
  321.                 # ... and if that succeeded:
  322.                 self.multiple = True
  323.             except debconf.DebconfError:
  324.                 pass
  325.         self.preseed('tzsetup/selected', 'false')
  326.         questions = ['^time/zone$', 'PROGRESS']
  327.         return ([clock_script], questions, env)
  328.  
  329.     def run(self, priority, question):
  330.         if question == 'time/zone':
  331.             if self.multiple:
  332.                 # Work around a debconf bug: REGISTER does not appear to
  333.                 # give a newly-registered question the same default as the
  334.                 # question associated with its template, unless we also
  335.                 # RESET it.
  336.                 self.db.reset(question)
  337.             zone = self.db.get(question)
  338.             # Some countries don't have a default zone, so just pick the
  339.             # first choice in the list.
  340.             if not zone:
  341.                 choices_c = self.choices_untranslated(question)
  342.                 if choices_c:
  343.                     zone = choices_c[0]
  344.             self.ui.set_timezone(zone)
  345.  
  346.         return Plugin.run(self, priority, question)
  347.  
  348.     def get_default_for_region(self, region):
  349.         try:
  350.             return self.db.get('tzsetup/country/%s' % region)
  351.         except debconf.DebconfError:
  352.             return None
  353.  
  354.     def collation_key(self, s):
  355.         if self.collator:
  356.             try:
  357.                 return self.collator.getCollationKey(s[0]).getByteArray()
  358.             except:
  359.                 pass
  360.         return s[0]
  361.  
  362.     def get_countries_for_region(self, region):
  363.         if region in self.regions: return self.regions[region]
  364.  
  365.         try:
  366.             codes = self.choices_untranslated('localechooser/countrylist/%s' % region)
  367.         except debconf.DebconfError:
  368.             codes = []
  369.         self.regions[region] = codes
  370.         return codes
  371.  
  372.     # Returns [('translated country name', None, 'region code')...] list
  373.     def build_region_pairs(self):
  374.         continents = self.choices_display_map('localechooser/continentlist')
  375.         names, codes = zip(*continents.items())
  376.         codes = [c.replace(' ', '_') for c in codes]
  377.         
  378.         nones = [None for key in continents]
  379.         pairs = zip(names, nones, codes)
  380.         pairs.sort(key=self.collation_key)
  381.         return pairs
  382.  
  383.     # Returns [('translated short list of countries', 'timezone')...] list
  384.     def build_shortlist_region_pairs(self, language_code):
  385.         try:
  386.             shortlist = self.choices_display_map('localechooser/shortlist/%s' % language_code)
  387.             # Remove any 'other' entry
  388.             for pair in shortlist.items():
  389.                 if pair[1] == 'other':
  390.                     del shortlist[pair[0]]
  391.                     break
  392.             names, codes = zip(*shortlist.items())
  393.             nones = [None for key in names]
  394.             shortlist = zip(names, codes, nones)
  395.             shortlist.sort(key=self.collation_key)
  396.             return shortlist
  397.         except debconf.DebconfError:
  398.             return []
  399.  
  400.     # Returns (shortlist, longlist)
  401.     def build_timezone_pairs(self, country_codes):
  402.         if len(country_codes) == 1:
  403.             shortlist = self.build_shortlist_timezone_pairs(country_codes[0])
  404.         else:
  405.             shortlist = []
  406.         
  407.         longlist = []
  408.         for country_code in country_codes:
  409.             longlist += self.build_longlist_timezone_pairs(country_code, sort=False)
  410.         longlist.sort(key=self.collation_key)
  411.         
  412.         # There may be duplicate entries in the shortlist and longlist.
  413.         # Basically, the shortlist is most useful when there are non-city
  414.         # timezones that may be more familiar to denizens of that country.
  415.         # Big examples are the US in which people tend to think in terms of
  416.         # Eastern/Mountain/etc.  If we see a match in tz code, prefer the
  417.         # longlist's translation and strip it from the shortlist.
  418.         # longlist tends to be more complete in terms of translation coverage
  419.         # (i.e. libicu is more translated than tzsetup)
  420.         shortcopy = shortlist[:]
  421.         for short_item in shortcopy:
  422.             for long_item in longlist:
  423.                 if short_item[1] == long_item[1]:
  424.                     shortlist.remove(short_item)
  425.                     break
  426.         
  427.         return (shortlist, longlist)
  428.  
  429.     def build_shortlist_timezone_pairs(self, country_code):
  430.         try:
  431.             shortlist = self.choices_display_map('tzsetup/country/%s' % country_code)
  432.             for pair in shortlist.items():
  433.                 # Remove any 'other' entry, we don't need it
  434.                 if pair[1] == 'other':
  435.                     del shortlist[pair[0]]
  436.             shortlist = shortlist.items()
  437.             shortlist.sort(key=self.collation_key)
  438.             return shortlist
  439.         except debconf.DebconfError, e:
  440.             return []
  441.  
  442.     def get_country_name(self, country):
  443.         # Relatively expensive algorithmically, but we don't call this often.
  444.         try:
  445.             continents = self.choices_untranslated('localechooser/continentlist')
  446.             for continent in continents:
  447.                 choices = self.choices_display_map('localechooser/countrylist/%s' % continent.replace(' ', '_'))
  448.                 for name, code in choices.items():
  449.                     if code == country:
  450.                         return name
  451.         except debconf.DebconfError, e:
  452.             print "Couldn't get country name for %s: %s" % (country, e)
  453.         return None
  454.  
  455.     def get_city_name_from_tzdata(self, tz):
  456.         city = tz.split('/', 1)[1]
  457.         # Iterate through tzdata's regions, check each region's tz list for
  458.         # our city.  Like get_country_name, this is inefficient (we could
  459.         # cache this info), but we don't need to run this often.
  460.         try:
  461.             areas = self.choices_untranslated('tzdata/Areas')
  462.             for area in areas:
  463.                 zones = self.choices_display_map('tzdata/Zones/%s' % area)
  464.                 for name, code in zones.items():
  465.                     if code == city:
  466.                         return name
  467.         except debconf.DebconfError, e:
  468.             print "Couldn't get city name for %s: %s" % (tz, e)
  469.         return None
  470.  
  471.     def get_fallback_translation_for_tz(self, country, tz):
  472.         # We want to return either 'Country' or 'Country (City)', translated
  473.         # First, get country name.  We need that regardless
  474.         country_name = self.get_country_name(country)
  475.         if country_name is None:
  476.             return None
  477.         show_city = len(self.tzdb.cc_to_locs[country]) > 1
  478.         if show_city:
  479.             # First, try tzdata's translation.
  480.             city_name = self.get_city_name_from_tzdata(tz)
  481.             if city_name is None:
  482.                 city_name = tz # fall back to ASCII name
  483.             city_name = city_name.split('/')[-1]
  484.             return "%s (%s)" % (country_name, city_name)
  485.         else:
  486.             return country_name
  487.  
  488.     # Returns [('translated long list of timezones', 'timezone')...] list
  489.     def build_longlist_timezone_pairs(self, country_code, sort=True):
  490.         if 'LANG' not in os.environ:
  491.             return [] # ?!
  492.         locale = os.environ['LANG'].rsplit('.', 1)[0]
  493.         tz_format = PyICU.SimpleDateFormat('VVVV', PyICU.Locale(locale))
  494.         now = time.time()*1000
  495.         rv = []
  496.         try:
  497.             locs = self.tzdb.cc_to_locs[country_code] # BV failed?
  498.         except:
  499.             # Some countries in tzsetup don't exist in zone.tab...
  500.             # Specifically BV (Bouvet Island) and
  501.             # HM (Heard and McDonald Islands).  Both are uninhabited.
  502.             locs = []
  503.         for location in locs:
  504.             tz_format.setTimeZone(PyICU.TimeZone.createTimeZone(location.zone))
  505.             translated = tz_format.format(now)
  506.             # Check if PyICU had a valid translation for this timezone.  If it
  507.             # doesn't, the returned string will look like GMT+0002 or somesuch.
  508.             # Sometimes the GMT is translated (like in Chinese), so we check
  509.             # for the number part.  PyICU does not indicate a 'translation
  510.             # failure' like this in any way...
  511.             if re.search('.*[-+][0-9][0-9]:?[0-9][0-9]$', translated):
  512.                 # Wasn't something that PyICU understood...
  513.                 name = self.get_fallback_translation_for_tz(country_code, location.zone)
  514.                 rv.append((name, location.zone))
  515.             else:
  516.                 rv.append((translated, location.zone))
  517.         if sort:
  518.             rv.sort(key=self.collation_key)
  519.         return rv
  520.  
  521.     # Returns [('translated long list of timezones', 'timezone')...] list
  522.     def build_longlist_timezone_pairs_by_continent(self, continent):
  523.         if 'LANG' not in os.environ:
  524.             return [] # ?
  525.         locale = os.environ['LANG'].rsplit('.', 1)[0]
  526.         tz_format = PyICU.SimpleDateFormat('VVVV', PyICU.Locale(locale))
  527.         now = time.time()*1000
  528.         rv = []
  529.         try:
  530.             regions = self.choices_untranslated('localechooser/countrylist/%s' % continent)
  531.             for region in regions:
  532.                 rv += self.build_longlist_timezone_pairs(region, sort=False)
  533.             rv.sort(key=self.collation_key)
  534.         except debconf.DebconfError:
  535.             pass
  536.         return rv
  537.  
  538.     def ok_handler(self):
  539.         zone = self.ui.get_timezone()
  540.         if zone is None:
  541.             zone = self.db.get('time/zone')
  542.         else:
  543.             self.preseed('time/zone', zone)
  544.         for location in self.tzdb.locations:
  545.             if location.zone == zone:
  546.                 self.preseed('debian-installer/country', location.country)
  547.                 break
  548.         Plugin.ok_handler(self)
  549.  
  550.     def cleanup(self):
  551.         Plugin.cleanup(self)
  552.         i18n.reset_locale(just_country=True)
  553.  
  554. class Install(InstallPlugin):
  555.     def prepare(self, unfiltered=False):
  556.         tzsetup_script = '/usr/lib/ubiquity/tzsetup/post-base-installer'
  557.         clock_script = '/usr/share/ubiquity/clock-setup-apply'
  558.  
  559.         if 'UBIQUITY_OEM_USER_CONFIG' in os.environ:
  560.             tzsetup_script += '-oem'
  561.  
  562.         return (['sh', '-c', '%s && %s' % (tzsetup_script, clock_script)], [])
  563.  
  564.     def install(self, target, progress, *args, **kwargs):
  565.         progress.info('ubiquity/install/timezone')
  566.         return InstallPlugin.install(self, target, progress, *args, **kwargs)
  567.